/*
 *
 * C++ MaJiang for 血流红中
 *
 * TuyooGame, 2021
 * zhouxin@tuyoogame.com
 *
 */
#ifndef __MJ_XUELIUHZ_CARD__
#define __MJ_XUELIUHZ_CARD__

#include <iostream>
#include <fstream>
#include <vector>
#include <set>
#include <algorithm>
#include <time.h>
#include <sys/time.h>
#include "mj_define.h"
#include "mjdata.h"
#include "mj_tiles.h"
#include "fan.h"

using namespace std;

typedef struct fandata_withcount {
    uint8_t hutile;
    int fancount;
    vector<MJ_FANXING> fandata;
} MJ_FANDATA;

typedef enum card_state : uint8_t {
    NOT_READY,
    READY
} CARD_STATE;

/*typedef struct calc_fan_request {
    uint64_t reqid;
    uint8_t now_tile;
    uint8_t tiles_len;
    uint8_t tiles[14];
    MJ_CPG_INFO cpg;
    uint8_t laizi;
    MJ_TILE_TYPE que;
} MJ_REQUEST;*/

#define INPUT_SIZE 1024
//udp最大包64K，一般结果不会这么大
#define OUTPUT_SIZE 65536

//血流红中...
class XueLiuHZCard {

public:
    uint8_t hongzhong_count; //红中个数
    CARD_STATE state; //初始化为NOT_READY，READY表示接收到了合法的输入，可以计算ting

    //原始牌型
    MJ_FX_INFO mfi_raw;

    //hasTing中调用calcFanCount时的牌型信息...
    //que, cpg和原始的一致，3个ti和now_tile对应当时的牌型
    MJ_FX_INFO mfi_calfx;

    //key: out_tile, value: vector of MJ_FANDATA...
    map<uint8_t, vector<MJ_FANDATA>> hu_result;

    XueLiuHZCard();
    XueLiuHZCard(vector<uint8_t> ts, uint8_t nt, vector<uint8_t> lz,
                 MJ_TILE_TYPE q, MJ_CPG_INFO *c, uint8_t hongzhong_count = 4, MJ_HU_TYPE ht = DIAN_PAO);

    ~XueLiuHZCard();

    //用assign的模式，节省对象创建的开销，建议XueLiuHZCard实例重复利用
    void assign(vector<uint8_t> ts, uint8_t nt, vector<uint8_t> lz,
                MJ_TILE_TYPE q, MJ_CPG_INFO *c, uint8_t hongzhong_count = 4, MJ_HU_TYPE ht = DIAN_PAO);

    //主要接口，返回运行时间，用于做cache，把最耗时的操作cache住
    uint32_t hasTing();

    //-------网络缓冲区读写接口--------
    //输入...
    //reqid nowtile tilelen tile1...tile14 laizi que cpgcount 基本信息20个数
    //tile com1...com4 seat type subtype cpg0,8个数
    //tile com1...com4 seat type subtype cpg1,8个数
    //tile com1...com4 seat type subtype cpg2,8个数
    //tile com1...com4 seat type subtype cpg3,8个数
    //hongzhong_count hu_type , 2个数
    //总共54个数,为了loadcache方便，用.替代空格分割这些数
    uint64_t request_id;  
    uint32_t input_size;
    char input_buffer[INPUT_SIZE];
    bool loadInput();

    //return MFIHash...
    uint32_t dumpInput(bool rewrite = true);

    //输出...
    //out_tile_count <out_tile_count>\n
    //out_tile <out_tile1>\n
    //<hutile> <fancount> <fan1> <fan2> ...\n
    //...
    //out_tile <out_tile2>\n
    //<hutile> <fancount> <fan1> <fan2> ...\n
    //...
    //后面为了loadcache方便，用.替代空格，用-替代\n
    uint32_t output_size;
    char output_buffer[OUTPUT_SIZE];
    void dumpOutput();
    void printHuResult();

private:
    vector<uint8_t> getTingTilesUniq();
    vector<uint8_t> getQueTiles();
    vector<uint8_t> getAllTiles();
    const vector<uint8_t> & getLeftTiles();
    void calcFanCount(uint8_t t, vector<uint8_t> ts, MJ_HU_TYPE h, int8_t seat, vector<MJ_FANDATA> &mjf);
    //输入mfi，输出fan_data
    void getFanXing(MJ_FX_INFO *mfi, vector<vector<MJ_FANXING>> & fan_datas);
    //输入fan_data, gen_count; 输出fan_dict和fan_count
    void getCurrentFanCount(vector<MJ_FANXING> &fan_data, int gen_count, 
                            map<MJ_FANXING, int> &fan_dict, int & fan_count);
    //输入mfi, 输出fan_data, fan_dict, fan_count
    void getMaxFanData(MJ_FX_INFO *mfi, vector<MJ_FANXING> & max_fan_data, 
                       map<MJ_FANXING, int> & max_fan_dict, int & max_fan_count);
    bool hasKeFan(MJ_FANXING f);
    bool canRmAllKe(MJ_FANXING f);
    uint64_t checkKeTiles(MJ_FX_INFO *mfi, MJ_FANXING fan, vector<uint8_t> &ketiles, uint64_t r, uint8_t start, bool rm=false);
    uint64_t checkYiTiaoLong(MJ_FX_INFO *mfi);
    uint64_t checkShuangAnKe(MJ_FX_INFO *mfi, uint64_t r);
    uint64_t checkZhuoWuKui(MJ_FX_INFO *mfi);
};

#endif
